/*  This file is Copyright 2010 Hampton Smith
 *
 *  This file is part of Adventure! a text-adventure game engine by Hampton
 *  Smith.
 *
 *  Adventure! is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Adventure! is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Adventure!.  If not, see http://www.gnu.org/licenses/.
 */

package edu.clemson.cs.hamptos.adventure;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.IOException;
import javax.swing.BoundedRangeModel;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;

/**
 * <p>A <code>JTerminalDisplay</code> is a scrolling, terminal-like display that
 * interprets HTML codes to style its text.</p>
 */
final class JTerminalDisplay 
        extends JScrollPane
        implements ComponentListener {

    private JEditorPane myTerminal;
    private HTMLDocument myTerminalDocument;
    private Element myRootElement;

    public JTerminalDisplay() {
        super(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        HTMLEditorKit k = new HTMLEditorKit();

        myTerminal = new JEditorPane();
        myTerminal.setContentType("text/html");
        myTerminal.setText("<span id='toplevel'>&nbsp;</span>");
        myTerminalDocument = (HTMLDocument) myTerminal.getDocument();
        myRootElement = myTerminalDocument.getElement("toplevel");

        //We're a special kind of JScrollPane, and a scroll pane needs a
        //component that it's providing a view of.  So here we specify that
        //we're providing a view of our "terminal".  We didn't do this in our
        //constructor call to "super" because there was no way to have the
        //terminal object yet--the "super" constructor always has to be the VERY
        //FIRST THING to run.
        super.setViewportView(myTerminal);

        myTerminal.setEditable(false);
        myTerminal.setBackground(Color.BLACK);
        myTerminal.setOpaque(true);

        //We'd like to scroll down to the bottom whenever new text is added,
        //so request that we be told when our terminal changes size
        myTerminal.addComponentListener(this);

        //We'd like to be as large as possible
        setPreferredSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));

        println("<font color='yellow'><b>This simple text-adventure " +
                "framework is Copyright 2010 Hampton Smith and released " +
                "under the GNU GPL version 3 or (at your option) any later " +
                "version.</font><br/>");
    }

    public void print(String text) {
        
        text = "<font color='white'>" + text + "</font>";

        try {
            myTerminalDocument.insertAfterEnd(myRootElement, text);

            //Request that the GUI system update our layout appropriately given
            //that we've just changed the size of the component we're viewing.
            revalidate();
        } catch (BadLocationException ex) {
            //This can't happen because we're inserting into an existing 
            //element.  Just in case, we'll change the BadLocationException
            //(which must be checked) into a RuntimeException (which needn't
            //be), so that we can ignore this possibility on the outside, but
            //still get the error in case something funky happens
            throw new RuntimeException(ex);
        } catch (IOException ex) {
            //Ditto.
            throw new RuntimeException(ex);
        }
    }

    public void println(String text) {
        print(text + "<br/>");
    }

    public void componentResized(ComponentEvent e) {
        //If this gets called, it means that our terminal changed sizes and
        //we'd like to scroll all the way to the bottom

        BoundedRangeModel vsbModel = getVerticalScrollBar().getModel();
        vsbModel.setValue(vsbModel.getMaximum());
    }

    public void componentMoved(ComponentEvent e) {

    }

    public void componentShown(ComponentEvent e) {

    }

    public void componentHidden(ComponentEvent e) {

    }
}
